/*
 *	CHANGE LOG
 * 
 * 01.02.01
 *
 *		12/27/2008 - DW - Added code to authorize user for method calls
 * 
 */


using System;
using System.Collections;
using System.Collections.Generic;
using DotNetNuke.Common.Utilities;
using DotNetNuke.Entities.Modules;
using DotNetNuke.Entities.Portals;
using DotNetNuke.Entities.Users;
using DotNetNuke.Modules.Announcements;
using MetaPostProvider.Announcements;
using DataProvider=DotNetNuke.Data.DataProvider;

namespace ITCrossing
{
	public class metaPostAnnouncementsProvider : IPublishable
    {
        #region " MetaPostExceptions "
        private const string STR_RecentPostsError = "RecentPostsError";
        private const string STR_FeatureNotImplemented = "FeatureNotImplemented";
        private const string STR_AnnouncementDoesNotExist = "AnnouncementDoesNotExist";
        #endregion

        # region IPublishable Members

        # region Public Properties
        public string ProviderKey
        { get { return MetaPostServices.GetFriendlyNameFromModuleDefinition(ModuleDefFriendlyString); } }
        /// <summary>
        /// ModuleDefFriendlyString represents the Friendly String name used by the ModuleDefinitions table (which doesn't change like the FriendlyString column in the DesktopModules table). This string value is "stable" in the earlier releases of DNN (4.8.2 or earlier).
        /// </summary>
        public string ModuleDefFriendlyString
        { get { return "Announcements"; } }
		public string ManifestFilePath
		{get { return "/DesktopModules/itcMetaPost/manifests/wlwAnnouncements.xml"; }}
		public string LocalizationFilePath
		{get { return "/DesktopModules/itcMetaPost/App_LocalResources/itcMetaPostAnnouncements"; }}
		public string ImageUploadPath
		{
			get
			{
				// This can be overridden with custom implementation if needed.  If
				// overridden, then a message should be placed in the ImagePath column
				// for your provider letting administrators know that administration of
				// the ImagePath is implemented elsewhere.  
				return MetaPostServices.GetProviderImageUploadPath(ProviderKey);
			}
		}
		public string AttachmentUploadPath
		{
			get
			{
				// For now, we'll just set this to the same as the image upload path
				return MetaPostServices.GetProviderAttachmentUploadPath(ProviderKey);
			}
		}
		public string SettingsUserControlPath
		{
			get { throw new NotImplementedException(); }
		}
        
		# endregion

        private ControllerFactory.AnnouncementsController_Proxy announcementController;

		# region Get Methods
        /// <summary>
        /// Gets an array of the announcements modules that the user is able to access for posting or opening announcements.
        /// </summary>
        /// <param name="userInfo"></param>
        /// <param name="portalSettings"></param>
        /// <param name="providerKey"></param>
        /// <returns></returns>
        /// <remarks>The method simply returns the results of 
        /// MetaPostServices.GetModuleInfo(). This service assumes 
        /// that the TabModuleId is the ModuleLevelId that is used. 
        /// As a result of this call to MetaPostServices.GetModuleInfo(), 
        /// all other methods of this provider should assume that the 
        /// supplied moduleLevelId is the TabModuleId, and must call 
        /// MetaPostServices.GetModuleIdByTabModuleId() to get the ModuleId</remarks>
        public ModuleInfoStruct[] GetModulesForUser(UserInfo userInfo, PortalSettings portalSettings, string providerKey)
		{
			return MetaPostServices.GetModulesForUser(
				providerKey, userInfo.UserID, portalSettings.PortalId);
		}

		public Item[] GetRecentItems(string moduleLevelId, UserInfo userInfo, PortalSettings portalSettings, int numberOfItems, RecentItemsRequestType requestType, string providerKey)
		{

			// Authorize user for method call
			MetaPostServices.AuthorizeUser(AuthorizationType.ModuleLevelId, moduleLevelId,
							   GetModulesForUser(userInfo, portalSettings, ProviderKey));			

			
			// Get the actual ModuleId since we're tracking the 
            // TabModuleId in the moduleLevelId parameter 
            // (see remarks on AnnouncementsProvider.GetModulesForUser()).
			int moduleId = MetaPostServices.GetModuleIdByTabModuleId(Convert.ToInt32(moduleLevelId));

			List<Item> itemArray = new List<Item>();

            announcementController = ControllerFactory.CreateController(portalSettings.PortalId, moduleId);
            ArrayList AnnouncementsArrayList = announcementController.GetAnnouncements(moduleId, Null.NullDate, Null.NullDate);

			if (AnnouncementsArrayList.Count > 0)
			{
				int count = 0;
				foreach (AnnouncementInfo AnnouncementInfo in AnnouncementsArrayList)
				{
					Item item; // = new Item();
                    item = AnnouncementsInfoAdapter.ExtractAnnouncemntInfo(AnnouncementInfo, portalSettings.PortalId);
                    //item.ItemId = AnnouncementInfo.ItemId.ToString();
                    //item.Title = HtmlUtils.StripTags(HttpUtility.HtmlDecode(AnnouncementInfo.Title), false);
                    //item.Content = HttpUtility.HtmlDecode(AnnouncementInfo.Description);
                    //item.DateCreated = AnnouncementInfo.CreatedDate;
					itemArray.Add(item);
					count++;
					if (count >= numberOfItems) break;
				}
			}
			else
			{
				throw new MetaPostException(STR_RecentPostsError,
											"There are no Announcements associated with this user account.  Please enter a user account which has been associated with an Announcements module.");
			}

			return itemArray.ToArray();
		}
	
        public Item GetItem(string itemId, UserInfo userInfo, PortalSettings portalSettings, ItemType itemType)
		{
			Item item = new Item();

			int moduleId = 0;

			moduleId = GetModuleIdFromItemId(itemId, portalSettings.PortalId);

			// Authorize user for method call
			MetaPostServices.AuthorizeUser(AuthorizationType.DnnModuleId, moduleId.ToString(),
							   GetModulesForUser(userInfo, portalSettings, ProviderKey));			


            announcementController = ControllerFactory.CreateController(portalSettings.PortalId, moduleId);
            AnnouncementInfo announcementInfo = announcementController.GetAnnouncement(Convert.ToInt32(itemId), moduleId);
            item = AnnouncementsInfoAdapter.ExtractAnnouncemntInfo(announcementInfo, portalSettings.PortalId);

			return item;
		}

		# endregion 

		# region Add, Edit and Delete Methods
		public string NewItem(string moduleLevelId, UserInfo userInfo, PortalSettings portalSettings, Item item)
		{

			// Authorize user for method call
			MetaPostServices.AuthorizeUser(AuthorizationType.ModuleLevelId, moduleLevelId,
							   GetModulesForUser(userInfo, portalSettings, ProviderKey));			

			List<string> images = MetaPostServices.GetImageListFromItem(ref item);
			
            int moduleId;
            moduleId = MetaPostServices.GetModuleIdByTabModuleId(Convert.ToInt32(moduleLevelId));

			# region Style Detection Code

			// This code is only needed in order to aid in style detection for the Announcements module.  Since it
			// doesn't show the answer in the default view of the page, WLW can't see the answer and can't 
			// download the styles.  We'll trick WLW into seeing the answer.  
			// NOTE:  This code is only needed in order to workaround the fact that the Announcements module doesn't
			// initially show the answer.
			if (item.StyleDetectionPost)
			{

			}
			

			# endregion

			item.ItemId = "-1"; // -1 is the default for a non-existing (new) item
            int AnnouncementId = AddAnnouncement(item, moduleId, userInfo);

			// Refresh the cache
			ModuleController moduleController = new ModuleController();
			ModuleInfo moduleInfo = moduleController.GetModule(moduleId, Null.NullInteger, false);
			MetaPostServices.RefreshCache(moduleInfo, moduleController);

			MetaPostServices.SaveItemImages(AnnouncementId, images, ProviderKey, portalSettings, userInfo.UserID);

			return AnnouncementId.ToString();
		}

		public bool EditItem(string moduleLevelId, UserInfo userInfo, PortalSettings portalSettings, Item item)
		{

			List<string> images = MetaPostServices.GetImageListFromItem(ref item);

			// Get the actual ModuleId 
			int moduleId = GetModuleIdFromItemId((string)item.ItemId, portalSettings.PortalId);

			// Authorize user for method call
			MetaPostServices.AuthorizeUser(AuthorizationType.DnnModuleId, moduleId.ToString(),
							   GetModulesForUser(userInfo, portalSettings, ProviderKey));			

			UpdateAnnouncement(item, moduleId, userInfo);

			// Refresh the cache
			ModuleController moduleController = new ModuleController();
			ModuleInfo moduleInfo = moduleController.GetModule(moduleId, Null.NullInteger, false);
			MetaPostServices.RefreshCache(moduleInfo, moduleController);

			MetaPostServices.SaveItemImages(Convert.ToInt32(item.ItemId), images, ProviderKey, portalSettings, userInfo.UserID);

			return true;
		}

		public bool DeleteItem(string itemId, UserInfo userInfo, PortalSettings portalSettings, ItemType itemType)
		{
			int moduleId = GetModuleIdFromItemId(itemId, portalSettings.PortalId);

			// Authorize user for method call
			MetaPostServices.AuthorizeUser(AuthorizationType.DnnModuleId, moduleId.ToString(),
							   GetModulesForUser(userInfo, portalSettings, ProviderKey));			


			# region Code for Cleaning up After Temporary Style Posts
			//
			// Removed to as not to change the data behind the scenes.  
			//
			//// The following code should only be executed if cleaning up after WLW
			//// tries to create a temporary style post.
			
			//string AnnouncementEnableAjax = MetaPostServices.GetTempStyleValue(userInfo.UserID, "AnnouncementEnableAjax");
			//if (!string.IsNullOrEmpty(AnnouncementEnableAjax))
			//{
			//    // Retrieve the ModuleId
			//    string AnnouncementQuestionTemplate =
			//        MetaPostServices.GetTempStyleValue(userInfo.UserID, "AnnouncementQuestionTemplate");
			//    DataProvider.Instance().UpdateModuleSetting(Convert.ToInt32(moduleId), "AnnouncementEnableAjax", AnnouncementEnableAjax);
			//    DataProvider.Instance().UpdateModuleSetting(Convert.ToInt32(moduleId), "AnnouncementQuestionTemplate", AnnouncementQuestionTemplate);
			//}
			# endregion

            ControllerFactory.AnnouncementsController_Proxy announcementController = ControllerFactory.CreateController(portalSettings.PortalId, moduleId);

            announcementController.Delete(Convert.ToInt32(itemId));

			return true;
		}

		# endregion

		# region Category Related Procedures
		public ItemCategoryInfo[] GetCategories(string moduleLevelId, UserInfo userInfo, PortalSettings portalSettings)
		{
			return null;
		}

		public bool SetItemCategories(string itemId, ItemCategory[] itemCategories, UserInfo userInfo,
		                        PortalSettings portalSettings)
		{
			// Not yet implemented.
			return true;
		}

		public ItemCategory[] GetItemCategories(string itemId, UserInfo userInfo,
		                                        PortalSettings portalSettings)
		{
			// Not yet implemented.
			return null;
		}

		public int NewCategory(string moduleLevelId, ITCrossing.NewItemCategory newCategory,  UserInfo userInfo, PortalSettings portalSettings)
		{
			throw new MetaPostException(STR_FeatureNotImplemented,
										"This feature is currently not implemented.");
		}

		# endregion

		#endregion

        # region Private Procedures Specific to the Announcements Module

        /// <summary>
		/// GetModuleIdFromItemId is needed for the Announcements provider for the GetItem method which calls it.
		/// </summary>
		/// <param name="itemId"></param>
		/// <returns></returns>
		/// <param name="portalId"></param>
		private int GetModuleIdFromItemId(string itemId, int portalId)
		{
            // TODO: See if this can be removed, as it is better to not use a sproc, if the same
            // info is available elsewhere. For further info, explore how the Ventrian News Article does it.
			int moduleId;
			// Get the moduleLevelId from the itemId
			object[] methodParams = { itemId };
			string SQL = "itcmetapost_Announcements_get_moduleid_by_itemid";
			moduleId = (int)DataProvider.Instance().ExecuteScalar(SQL, methodParams);
			return moduleId;
		}

        /// <summary>
        /// AddAnnouncement is the procedure which handles adding a new Announcement to the database.
        /// </summary>
        /// <param name="item"></param>
        /// <param name="moduleId"></param>
        /// <param name="userInfo"></param>
        /// <returns></returns>
        private int AddAnnouncement(Item item, int moduleId, UserInfo userInfo)
        {
            announcementController = ControllerFactory.CreateController(userInfo.PortalID, moduleId);

            int announcementId = 0;

            AnnouncementInfo announcementInfo = new AnnouncementInfo();

            item.ItemId = -1; // Default the item ID to -1, as this is being added
            AnnouncementsInfoAdapter.FillAnnouncementInfo(ref announcementInfo, item, moduleId, userInfo);            

            announcementId = announcementController.Add(announcementInfo);

            // TODO: See Footnote 1 at the end of this file...

            return announcementId;
        }

        /// <summary>
		/// UpdateAnnouncement is the procedure which handles updating the database with the
		/// changes made to the Announcement entry.
		/// </summary>
		/// <param name="item"></param>
		/// <param name="moduleId"></param>
		/// <param name="userInfo"></param>
		private void UpdateAnnouncement(Item item, int moduleId, UserInfo userInfo)
		{
            // Updating an announcement should not "empty" AnnouncementInfo data
            // that cannot be mapped from the Item struct, so we need to get
            // the AnnouncementInfo and then modify the "changed" parts.
            announcementController = ControllerFactory.CreateController(userInfo.PortalID, moduleId);

            AnnouncementInfo announcementInfo = announcementController.GetAnnouncement(Convert.ToInt32(item.ItemId), moduleId);

            if (announcementInfo == null)
                throw new MetaPostException(STR_AnnouncementDoesNotExist, "The announcement cannot be updated because it does not exist.");

            AnnouncementsInfoAdapter.FillAnnouncementInfo(ref announcementInfo, item, moduleId, userInfo);

			announcementController.UpdateAnnouncement(announcementInfo);

            // TODO: See Footnote 1 at the end of this file...
        }
		# endregion
	}
}
/* Footnote 1: See if the updating of the cache is needed...
 * Version 04.00.01, EditAnnouncements.ascx.vb, lines 236-244:
        Dim objAnnouncements As New AnnouncementsController
        If Common.Utilities.Null.IsNull(itemId) Then
            objAnnouncements.AddAnnouncement(objAnnouncement)
        Else
            objAnnouncements.UpdateAnnouncement(objAnnouncement)
        End If

        ' refresh cache
        ModuleController.SynchronizeModule(ModuleId)
 * 
 * Version 03.03.05, EditAnnouncements.ascx.vb, lines 222-230
        Dim objAnnouncements As New AnnouncementsController
        If Common.Utilities.Null.IsNull(itemId) Then
            objAnnouncements.AddAnnouncement(objAnnouncement)
        Else
            objAnnouncements.UpdateAnnouncement(objAnnouncement)
        End If

        ' refresh cache
        SynchronizeModule()
 */
